/*
MIT License

Copyright (c) 2022 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo/loom
*/

#include "simodo/variable/VariableSetWrapper.h"
#include "simodo/bormental/DrBormental.h"
#include "simodo/inout/format/fmt.h"

#include <cassert>

using namespace simodo::bormental;
using namespace simodo::variable;

VariableSetWrapper_mutable::VariableSetWrapper_mutable(VariableSet_t & set)
    : _set(set)
    , _begin_index(0)
    , _end_index(set.size())
{
}

VariableSetWrapper_mutable::VariableSetWrapper_mutable(VariableSet_t & set, size_t begin_index)
    : _set(set)
    , _begin_index(begin_index)
    , _end_index(set.size())
{
    assert(_begin_index <= _end_index && _end_index <= set.size());
}

VariableSetWrapper_mutable::VariableSetWrapper_mutable(VariableSet_t & set, size_t begin_index, size_t end_index)
    : _set(set)
    , _begin_index(begin_index)
    , _end_index(end_index)
{
    assert(begin_index <= end_index && end_index <= set.size());
}

Variable & VariableSetWrapper_mutable::at(size_t index)
{
    // Учитываем возможность изменения размера рабочего набора данных (не связанное с многопоточностью)
    size_t end_index = (_set.size() < _end_index) ? _set.size() : _end_index;

    if (_begin_index > end_index)
        throw DrBormental("VariableSetWrapper_mutable::at", inout::fmt("Invalid dataset resizing"));

    // Выход индекса за границу набора данных
    if (_begin_index + index >= end_index)
        throw DrBormental("VariableSetWrapper_mutable::at", 
                        inout::fmt("Attempt to handle invalid offset (%1) in Variable Set Wrapper (size: %2)")
                        .arg(index)
                        .arg(end_index-_begin_index));

    return _set[_begin_index + index];
}

const Variable & VariableSetWrapper_mutable::at(size_t index) const
{
    // Учитываем возможность изменения размера рабочего набора данных (не связанное с многопоточностью)
    size_t end_index = (_set.size() < _end_index) ? _set.size() : _end_index;

    if (_begin_index > end_index)
        throw DrBormental("VariableSetWrapper_mutable::at", "Invalid dataset resizing");

    // Выход индекса за границу набора данных
    if (_begin_index + index >= end_index)
        throw DrBormental("VariableSetWrapper_mutable::at", 
                        inout::fmt("Attempt to handle invalid offset (%1) in Variable Set Wrapper (size: %2)")
                        .arg(index)
                        .arg(end_index-_begin_index));

    return _set[_begin_index + index];
}

size_t VariableSetWrapper_mutable::size() const
{
    // Учитываем возможность изменения размера рабочего набора данных (не связанное с многопоточностью)
    size_t end_index = (_set.size() < _end_index) ? _set.size() : _end_index;

    if (_begin_index > end_index)
        throw DrBormental("VariableSetWrapper_mutable::size", inout::fmt("Invalid dataset resizing"));

    return _end_index-_begin_index;
}

VariableSetWrapper::VariableSetWrapper(const VariableSetWrapper_mutable & wrapper) 
    : _set(wrapper.set()) 
    , _begin_index(wrapper.begin_index())
    , _end_index(wrapper.end_index())
{
}

VariableSetWrapper::VariableSetWrapper(const VariableSet_t & set)
    : _set(set)
    , _begin_index(0)
    , _end_index(set.size())
{
}

VariableSetWrapper::VariableSetWrapper(const VariableSet_t & set, size_t begin_index)
    : _set(set)
    , _begin_index(begin_index)
    , _end_index(set.size())
{
    assert(begin_index <= _end_index && _end_index <= set.size());
}

VariableSetWrapper::VariableSetWrapper(const VariableSet_t & set, size_t begin_index, size_t end_index)
    : _set(set)
    , _begin_index(begin_index)
    , _end_index(end_index)
{
    assert(begin_index <= end_index && end_index <= set.size());
}

const Variable &VariableSetWrapper::at(size_t index) const
{
    // Учитываем возможность изменения размера рабочего набора данных (не связанное с многопоточностью)
    size_t end_index = (_set.size() < _end_index) ? _set.size() : _end_index;

    if (_begin_index > end_index)
        throw DrBormental("VariableSetWrapper::at", inout::fmt("Invalid dataset resizing"));

    // Выход индекса за границу набора данных
    if (_begin_index + index >= end_index)
        throw DrBormental("VariableSetWrapper::at", 
                        inout::fmt("Attempt to handle invalid offset (%1) in Variable Set Wrapper (size: %2)")
                        .arg(index)
                        .arg(end_index-_begin_index));

    return _set[_begin_index + index];
}

size_t VariableSetWrapper::size() const
{
    // Учитываем возможность изменения размера рабочего набора данных (не связанное с многопоточностью)
    size_t end_index = (_set.size() < _end_index) ? _set.size() : _end_index;

    if (_begin_index > end_index)
        throw DrBormental("VariableSetWrapper::size", inout::fmt("Invalid dataset resizing"));

    return _end_index-_begin_index;
}

